package game.client.jme;

import com.jme3.app.SimpleBulletApplication;
import com.jme3.bullet.collision.shapes.BoxCollisionShape;
import com.jme3.bullet.collision.shapes.MeshCollisionShape;
import com.jme3.bullet.collision.shapes.SphereCollisionShape;
import com.jme3.bullet.nodes.PhysicsCharacterNode;
import com.jme3.bullet.nodes.PhysicsNode;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Sphere;
import com.jme3.util.TangentBinormalGenerator;
import game.client.net.WorldObjectListener;
import game.common.world.Vector;

/**
 *
 * @author ss
 */
public class GameWorld extends SimpleBulletApplication implements WorldObjectListener {

    public void objectMoved(String obj, Vector newPos) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public void objectDeleted(String obj) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    enum Turning {
        TURN_NO,
        TURN_LEFT,
        TURN_RIGHT
    }

    private PhysicsCharacterNode    my_char;
    private float                   my_char_speed = 0f;
    private float                   my_char_angle = 0f;
    private Turning                 my_char_turning = Turning.TURN_NO;
    private Quaternion              my_char_quat = Quaternion.IDENTITY.clone();

    @Override
    public void simpleInitApp() {
        setFloor();
        setMyChar();
        setDecor();
        setupInput();
    }

    @Override
    public void simpleUpdate(float tpf) {

        updateCam();
        updateMyChar(tpf);
    }

    private void updateCam() {
        cam.setLocation(my_char.getWorldTranslation().clone().add(
                    FastMath.sin(FastMath.DEG_TO_RAD*my_char_angle) * 20,
                    10,
                    FastMath.cos(FastMath.DEG_TO_RAD*my_char_angle) * 20)
                );

        cam.lookAt(my_char.getLocalTranslation(), Vector3f.ZERO );
    }

    private void updateMyChar(float tpf) {

        boolean is_turning = true;

        switch( my_char_turning ) {
            case TURN_LEFT: {
                my_char_angle += 0.2;
            } break;
            case TURN_RIGHT: {
                my_char_angle -= 0.2;
            } break;
            case TURN_NO: {
                is_turning = false;
            } break;

        }

        my_char_quat.fromAngleAxis(FastMath.DEG_TO_RAD*my_char_angle, Vector3f.UNIT_Y);

        if( is_turning )
            my_char.setLocalRotation(my_char_quat);

        if( my_char_speed != 0 ) {
            my_char.setWalkDirection( my_char_quat.mult(Vector3f.UNIT_Z.mult(my_char_speed)) );
        } else {
            my_char.setWalkDirection(new Vector3f( 0,0,0) );
        }
    }

    private void setFloor() {

        Material mat = new Material(assetManager, "Common/MatDefs/Misc/SolidColor.j3md");
        mat.setColor("m_Color", ColorRGBA.Green);

        // the floor, does not move (mass=0)
        Geometry geom5=new Geometry("floor",new Box(Vector3f.ZERO,100f,1f,100f));
        geom5.setMaterial(mat);
        geom5.updateGeometricState();
        PhysicsNode node3=new PhysicsNode(geom5,new BoxCollisionShape(new Vector3f(100,1,100)),0);
        node3.setLocalTranslation(new Vector3f(0f,-6,0f));
        rootNode.attachChild(node3);
        node3.updateModelBound();
        node3.updateGeometricState();
        getPhysicsSpace().add(node3);
    }

    private void setMyChar() {
        Sphere rock = new Sphere(32,32, 2f);
        Geometry shiny_rock = new Geometry("Shiny rock", rock);
        rock.setTextureMode(Sphere.TextureMode.Projected); // better quality on spheres
        TangentBinormalGenerator.generate(rock);           // for lighting effect
        Material mat_lit = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
        mat_lit.setTexture("m_DiffuseMap", assetManager.loadTexture("Textures/Terrain/Pond/Pond.png"));
        mat_lit.setTexture("m_NormalMap", assetManager.loadTexture("Textures/Terrain/Pond/Pond_normal.png"));
        mat_lit.setFloat("m_Shininess", 5f); // [0,128]
        shiny_rock.setMaterial(mat_lit);
        shiny_rock.setLocalTranslation(0,0,0); // Move it a bit
        shiny_rock.rotate(1.6f, 0, 0);          // Rotate it a bit
        rootNode.attachChild(shiny_rock);
        /** Must add a light to make the lit object visible! */
        DirectionalLight sun = new DirectionalLight();
        sun.setDirection(new Vector3f(1,0,-2).normalizeLocal());
        sun.setColor(ColorRGBA.White);
        rootNode.addLight(sun);

        //Material mat = new Material(assetManager, "Common/MatDefs/Misc/SolidColor.j3md");
        //mat.setColor("m_Color", ColorRGBA.Blue);
//      Add a physics sphere to the world
        //Box box=new Box(new Vector3f(0,0,0), 1, 1, 2);
        //Geometry geom=new Geometry("box",box);
        //geom.setMaterial(mat);

        my_char = new PhysicsCharacterNode(shiny_rock, new SphereCollisionShape(1), .1f);
        my_char.setLocalTranslation(new Vector3f(3,6,0));
        my_char.updateModelBound();

        rootNode.attachChild(my_char);
        getPhysicsSpace().add(my_char);
    }

    private void setDecor() {
        Material mat = new Material(assetManager, "Common/MatDefs/Misc/SolidColor.j3md");
        mat.setColor("m_Color", ColorRGBA.Yellow);

        for( int i=0; i< 20; i++ ) {
            Geometry geom4=new Geometry("node"+i,new Sphere(16,16,1.2f));
            geom4.setMaterial(mat);
            PhysicsNode node2=new PhysicsNode(geom4,new MeshCollisionShape(geom4.getMesh()),.01f);
            node2.setLocalTranslation(new Vector3f(FastMath.nextRandomInt(-50, 50),-4,FastMath.nextRandomInt(-50, 50)));
            rootNode.attachChild(node2);
            getPhysicsSpace().add(node2);
        }
    }

    private void setupInput() {

        flyCam.setEnabled(false);

        inputManager.addMapping("Up", new KeyTrigger(keyInput.KEY_UP));
        inputManager.addMapping("Down", new KeyTrigger(keyInput.KEY_DOWN));
        inputManager.addMapping("Left", new KeyTrigger(keyInput.KEY_LEFT));
        inputManager.addMapping("Right", new KeyTrigger(keyInput.KEY_RIGHT));
        inputManager.addMapping("Space", new KeyTrigger(keyInput.KEY_SPACE));

        inputManager.addListener(analogListener, new String[]{"Up", "Down", "Left", "Right", "Space"});
    }

    private ActionListener analogListener = new ActionListener() {
        public void onAction(String name, boolean keyPressed, float tpf) {
            if (name.equals("Up")) {
                if( keyPressed ) {
                    my_char_speed = -1;
                } else {
                    my_char_speed = 0;
                }

            } else
            if (name.equals("Down")) {
                if( keyPressed ) {
                    my_char_speed = 1;
                } else {
                    my_char_speed = 0;
                }
            } else
            if (name.equals("Left")) {
                if( keyPressed ) {
                    my_char_turning = Turning.TURN_LEFT;
                }  else {
                    my_char_turning = Turning.TURN_NO;
                }
            } else
            if (name.equals("Right")) {
                if( keyPressed ) {
                    my_char_turning = Turning.TURN_RIGHT;
                }  else {
                    my_char_turning = Turning.TURN_NO;
                }
            } else
            if (name.equals("Space")) {
                if( keyPressed )
                    my_char.jump();
            }
        }
    };
}
